---
title: Astro 콘텐츠 로더 API
sidebar:
  label: 콘텐츠 로더 API
i18nReady: true
---
import Since from '~/components/Since.astro';

Astro의 콘텐츠 로더 API를 사용하면 로컬 또는 원격의 모든 소스에서 데이터를 로드하고 [콘텐츠 컬렉션](/ko/guides/content-collections/)을 관리하기 위해 Astro의 콘텐츠 레이어와 상호 작용할 수 있습니다.

## 로더가 무엇인가요?

Astro 로더를 사용하면 페이지와 컴포넌트에서 사용할 수 있는 [콘텐츠 컬렉션](/ko/guides/content-collections/)에 데이터를 로드할 수 있습니다. [내장된 `glob()`과 `file()` 로더](/ko/guides/content-collections/#내장-로더)는 파일 시스템에서 콘텐츠를 로드하는 데 사용되며, 다른 소스에서 콘텐츠를 로드하기 위한 자체 로더를 만들 수 있습니다.

각 컬렉션에는 [스키마에 정의된 로더](/ko/guides/content-collections/#컬렉션-loader-정의)가 필요합니다. 프로젝트의 `src/content.config.ts` 파일에서 로더를 인라인으로 정의하거나, 여러 컬렉션 간에 하나의 로더를 공유하거나, 심지어 [로더를 NPM 패키지로 게시](/ko/reference/publish-to-npm/)하여 다른 사람들과 공유하고 통합 라이브러리에 포함시킬 수도 있습니다.

## 내장 로더

Astro는 컬렉션을 가져오는 데 도움이 되는 두 가지 내장 로더를 제공합니다. 두 로더 모두 다양한 사용 사례에 적합한 옵션을 제공합니다.

### `glob()` 로더

<p>

**타입:** <code>(options: GlobOptions) => <a href="#loader-객체">Loader</a></code><br />
<Since v="5.0.0" />
</p>

`glob()` 로더는 파일 시스템의 어디에서나 파일 디렉터리로부터 항목들을 생성합니다. 지원되는 파일 형식은 Markdown, MDX, Markdoc, JSON, YAML 및 TOML 파일입니다.

이 로더는 다음과 같은 속성을 가진 객체를 받습니다: `pattern`, `base`(선택사항), 그리고 `generateId`(선택사항).

```ts title="src/content.config.ts" {2,6,11,16-20}
import { defineCollection } from 'astro:content';
import { glob } from 'astro/loaders';

const pages = defineCollection({
  /* pages 디렉터리에 있는 모든 Markdown 파일을 가져옵니다. */
  loader: glob({ pattern: "**/*.md", base: "./src/data/pages" }),
  schema: /* ... */
});
const blog = defineCollection({
  /* blog 디렉터리에 있는 모든 Markdown과 MDX 파일을 가져옵니다. */
  loader: glob({ pattern: "**/*.(md|mdx)", base: "./src/data/blog" }),
  schema: /* ... */
});
const authors = defineCollection({
  /* authors 디렉터리에 있는 모든 JSON 파일을 가져오면서 ID의 대문자를 유지합니다. */
  loader: glob({
    pattern: '**/*.json',
    base: "./src/data/authors",
    generateId: ({ entry }) => entry.replace(/\.json$/, ''),
  }),
  schema: /* ... */
});
```

#### `pattern`

<p>

**타입:** `string | string[]`
</p>

`pattern` 속성은 glob 매칭(예: 와일드카드, 글롭스타)을 사용하는 문자열 또는 문자열 배열을 받습니다. 패턴은 매칭할 엔트리 파일들의 기본 디렉터리를 기준으로 상대 경로여야 합니다.

사용할 수 있는 구문에 대해 더 자세히 알아보려면 [micromatch 문서](https://github.com/micromatch/micromatch#matching-features)를 참고하세요. 또한 [DigitalOcean Glob Tool](https://www.digitalocean.com/community/tools/glob)과 같은 온라인 도구를 사용하여 패턴의 유효성을 확인할 수 있습니다.

#### `base`

<p>

**타입:** `string | URL`<br />
**기본값:** `"."`
</p>

`pattern`을 해석할 때 기준이 되는 디렉터리의 상대 경로 또는 [URL](https://developer.mozilla.org/ko/docs/Web/API/URL)입니다.

#### `generateId()`

<p>

**타입:** `(options: GenerateIdOptions) => string`
</p>

컬렉션의 각 항목마다 고유한 문자열을 반환하는 콜백 함수입니다. 이 함수는 다음과 같은 속성들을 가진 객체를 매개변수로 받습니다:
* `entry` - 기본 디렉터리를 기준으로 한 항목 파일의 경로
* `base` - 기본 디렉터리 [URL](https://developer.mozilla.org/ko/docs/Web/API/URL)
* `data` - 파싱된, 검증되지 않은 항목 데이터

기본적으로 [`github-slugger`](https://github.com/Flet/github-slugger)를 사용하여 [케밥-케이스](https://developer.mozilla.org/ko/docs/Glossary/Kebab_case) 형식의 슬러그를 생성합니다.

### `file()` 로더

<p>

**타입:** <code>(fileName: string, options?: FileOptions) => <a href="#loader-객체">Loader</a></code><br />
<Since v="5.0.0" />
</p>

`file()` 로더는 고유한 `id` 필드를 가진 객체의 배열을 포함하는 단일 파일 또는 ID를 키로, 항목을 값으로 가지는 객체로부터 항목을 생성합니다. JSON, YAML 또는 TOML 파일을 지원하며, 기본적으로 파싱할 수 없는 데이터 파일을 위해 사용자 정의 `parser`를 제공할 수 있습니다.

이 로더는 `fileName` 속성을 받으며, 선택적으로 두 번째 인수로 객체를 받습니다.

```ts title="src/content.config.ts" {2,6,11-13}
import { defineCollection } from 'astro:content';
import { file } from 'astro/loaders';

const authors = defineCollection({
  /* JSON 파일에서 모든 항목을 검색합니다. */
  loader: file("src/data/authors.json"),
  schema: /* ... */
});
const products = defineCollection({
  /* 사용자 정의 파서를 사용하여 CSV 파일에서 모든 항목을 검색합니다. */
  loader: file("src/data/products.csv", {
    parser: (fileContent) => { /* 파서 로직 */ },
  }),
  schema: /* ... */
});
```

#### `fileName`

<p>

**타입:** `string`
</p>

루트 디렉터리를 기준으로 로드할 파일의 경로를 설정합니다.

#### Options

<p>

**타입:** `FileOptions`
</p>

다음 속성을 가진 선택적 객체입니다:

##### `parser()`

<p>

**타입:** `(text: string) => Record<string, Record<string, unknown>> | Array<Record<string, unknown>>`
</p>

파일의 콘텐츠에서 컬렉션을 생성하는 콜백 함수입니다. 기본적으로 지원되지 않는 파일(예: `.csv`)을 처리하거나 [중첩된 `.json` 문서](/ko/guides/content-collections/#중첩된-json-문서)를 사용할 때 사용합니다.

## 로더 타입

로더는 항목 배열을 반환하는 단순한 함수로 정의하거나, 로딩 프로세스를 더 잘 제어할 수 있는 강력한 객체 콘텐츠 로더 API로 정의할 수 있습니다. 

### 인라인 로더

인라인 로더는 항목의 배열이나 객체를 반환하는 비동기 함수입니다. 이것은 특히 `src/content.config.ts` 파일에 인라인으로 정의된 간단한 로더에 사용하세요.

이 함수는 비동기일 수 있으며 각각 고유한 `id` 필드를 포함하는 항목의 배열이나, 각 키가 고유 ID이고 각 값이 항목인 객체를 반환해야 합니다. 로더가 호출될 때마다 저장소를 지우고 모든 항목을 다시 로드합니다.

```ts title="src/content.config.ts"
const countries = defineCollection({
  loader: async () => {
    const response = await fetch("https://restcountries.com/v3.1/all");
    const data = await response.json();
    // id 속성을 가진 항목의 배열이나
    // ID를 키로, 항목을 값으로 가지는 객체를 반환해야 합니다
    return data.map((country) => ({
      id: country.cca3,
      ...country,
    }));
  },
  schema: /* ... */
});
```

### 객체 로더

로더는 빌드 시점에 데이터를 가져오고 데이터 저장소를 업데이트하기 위해 호출되는 `load()` 메서드를 가진 객체입니다. 이는 항목을 점진적으로 업데이트하거나 필요한 경우에만 저장소를 지우는 것을 허용합니다. 또한 데이터를 검증하고 정적 타입을 생성하는 데 사용할 수 있는 항목의 스키마를 정의할 수 있습니다.

권장되는 패턴은 Astro 통합이나 Vite 플러그인을 정의하는 것과 같은 방식으로, 구성 옵션을 받아 로더 객체를 반환하는 함수를 정의하는 것입니다.

```ts title=loader.ts
import type { Loader, LoaderContext } from 'astro/loaders';
import { z } from 'astro:content';
import { loadFeedData } from "./feed.js";

// 로더에 필요한 모든 옵션을 정의
export function myLoader(options: { url: string, apiKey: string }): Loader {
  // 로더 구성
  const feedUrl = new URL(options.url);
  // 로더 객체 반환
  return {
    name: "my-loader",
    // 컬렉션 업데이트 시 호출
    load: async (context: LoaderContext): Promise<void> => {
      // 데이터 로드 및 저장소 업데이트
      const response = await loadFeedData(feedUrl, options.apiKey);
    },
    // 선택적으로, 항목의 스키마 정의
    // 사용자 정의 스키마에 의해 재정의됨
    schema: async () => z.object({
      // ...
    })
  };
}
```

이러한 구성 옵션은 컬렉션을 정의할 때 설정할 수 있습니다:

```ts title="src/content.config.ts"  {2,5-8}  
import { defineCollection, z } from 'astro:content';  
import myLoader from '../../loader.ts';  

const blog = defineCollection({  
  loader: myLoader({
    url: "https://api.example.com/posts",
    apiKey: "my-secret",
  }),  
  schema: /* ... */  
});  
```

## 객체 로더 API

[인라인 로더](#인라인-로더)를 위한 API는 매우 간단하며 위에서 보여드렸습니다. 이 섹션에서는 객체 로더를 정의하기 위한 API를 보여줍니다.

### `Loader` 객체

로더 객체는 다음과 같은 속성을 가집니다:

#### `name`

<p>

**타입**: `string`
</p>

로그 및 [조건부 로딩](/ko/reference/integrations-reference/#refreshcontent-옵션)에 사용되는 로더의 고유한 이름입니다.

#### `load`

<p>

**타입**: <code>(context: <a href="#loadercontext">LoaderContext</a>) => Promise&lt;void&gt;</code>
</p>

데이터를 로드하고 스토어를 업데이트하기 위해 빌드 시점에 호출되는 비동기 함수입니다. 자세한 내용은 [`LoaderContext`](#loadercontext)를 참조하세요.

#### `schema`

<p>

**타입**: `ZodSchema | Promise<ZodSchema> | (() => ZodSchema | Promise<ZodSchema>)`
</p>

항목의 형태를 정의하는 선택적 [Zod 스키마](/ko/guides/content-collections/#zod를-사용한-데이터-타입-정의)입니다. 이는 데이터를 검증하고 컬렉션에 대한 TypeScript 타입을 생성하는 데 사용됩니다.

함수가 제공되는 경우, 스키마를 생성하기 위해 `load()` 전 빌드 시점에 호출됩니다. 이를 통해 구성 옵션을 기반으로 하거나 API를 검사하여 스키마를 동적으로 생성할 수 있습니다.

### `LoaderContext`

이 객체는 로더의 `load()` 메서드에 전달되며, 다음과 같은 속성들을 포함합니다:

#### `collection`

<p>

**타입**: `string`
</p>

컬렉션의 고유한 이름입니다. 이는 `src/content.config.ts` 파일의 `collections` 객체에 있는 키입니다.

#### `store`

<p>

**타입**: [`DataStore`](#datastore)
</p>

실제 데이터를 저장하는 데이터베이스입니다. 새로운 항목으로 스토어를 업데이트하기 위해 이를 사용하세요. 자세한 내용은 [`DataStore`](#datastore)를 참조하세요.

#### `meta`

<p>

**타입**: `MetaStore`
</p>

동기화 토큰이나 마지막 수정 시간과 같은 항목을 위해 설계된 컬렉션 범위의 키-값 저장소입니다. 이 메타데이터는 컬렉션 데이터와 함께 빌드 간 유지되지만 로더에서만 사용할 수 있습니다.

```ts
const lastModified = meta.get("lastModified");
// ...
meta.set("lastModified", new Date().toISOString());
```

#### `logger`

<p>

**타입**: [`AstroIntegrationLogger`](/ko/reference/integrations-reference/#astrointegrationlogger)
</p>

콘솔에 메시지를 로깅하는 데 사용할 수 있는 로거입니다. 로그 메시지에 로더 이름을 포함하는 더 유용한 로그를 위해 `console.log` 대신 이것을 사용하세요. 자세한 내용은 [`AstroIntegrationLogger`](/ko/reference/integrations-reference/#astrointegrationlogger)를 참조하세요.

#### `config`

<p>

**타입**: `AstroConfig`
</p>

모든 기본값이 적용된 완전히 해결된 Astro 구성 객체입니다. 자세한 내용은 [구성 참조](/ko/reference/configuration-reference/)를 확인하세요.

#### `parseData`

<p>

**타입**: `(props: ParseDataOptions<TData>) => Promise<TData>`
</p>

컬렉션 스키마에 따라 데이터를 검증하고 파싱합니다. 데이터 스토어에 저장하기 전에 데이터를 검증하고 파싱하려면 이 함수에 데이터를 전달하세요.

```ts title=loader.ts {14-17}
import type { Loader } from "astro/loaders";
import { loadFeed } from "./feed.js";

export function feedLoader({ url }): Loader {
  const feedUrl = new URL(url);
  return {
    name: "feed-loader",
    load: async ({ store, logger, parseData, meta, generateDigest }) => {
      logger.info("Loading posts");
      const feed = loadFeed(feedUrl);
      store.clear();

      for (const item of feed.items) {
        const data = await parseData({
          id: item.guid,
          data: item,
        });
        store.set({
          id,
          data,
        });
      }
    },
  };
}
```

#### `renderMarkdown`

<p>

**타입**: `(markdown: string) => Promise<RenderedContent>`
<Since v="5.9.0" />
</p>

`RenderedContent` 객체를 반환하면서 Markdown 문자열을 HTML로 렌더링합니다.

이 기능을 사용하면 Astro의 내장 `glob` 로더와 동일한 Markdown 처리 방식을 사용하여 로더에서 Markdown 콘텐츠를 직접 렌더링할 수 있습니다. 또한 [본문 콘텐츠를 렌더링](/ko/guides/content-collections/#본문-콘텐츠-렌더링)하기 위한 `render()` 함수와 `<Content />` 컴포넌트에 접근할 수도 있습니다.

사용자가 [페이지에서 콘텐츠를 렌더링](/ko/guides/content-collections/#본문-콘텐츠-렌더링)할 수 있도록 이 객체를 [DataEntry](#dataentry) 객체의 [rendered](#rendered) 필드에 할당하세요.

```ts title=loader.ts {16-17}
import type { Loader } from 'astro/loaders';
import { loadFromCMS } from './cms.js';

export function myLoader(settings): Loader {
  return {
    name: 'cms-loader',
    async load({ renderMarkdown, store }) {
      const entries = await loadFromCMS();

      store.clear();

      for (const entry of entries) {
        store.set({
          id: entry.id,
          data: entry,
          // 각 항목에 Markdown 콘텐츠를 나타내는 'content' 필드가 있다고 가정합니다.
          rendered: await renderMarkdown(entry.content),
        });
      }
    },
  };
}
```

#### `generateDigest`

<p>

**타입**: `(data: Record<string, unknown> | string) => string`
</p>

객체나 문자열의 비암호화 콘텐츠 다이제스트를 생성합니다. 이는 항목의 [digest 필드](#digest)를 설정하여 데이터가 변경되었는지 추적하는 데 사용할 수 있습니다.

```ts title=loader.ts {19,24}
import type { Loader } from "astro/loaders";
import { loadFeed } from "./feed.js";

export function feedLoader({ url }): Loader {
  const feedUrl = new URL(url);
  return {
    name: "feed-loader",
    load: async ({ store, logger, parseData, meta, generateDigest }) => {
      logger.info("Loading posts");
      const feed = loadFeed(feedUrl);
      store.clear();

      for (const item of feed.items) {
        const data = await parseData({
          id: item.guid,
          data: item,
        });

        const digest = generateDigest(data);

        store.set({
          id,
          data,
          digest,
        });
      }
    },
  };
}
```

#### `watcher`

<p>

**타입**: `FSWatcher`
</p>

개발 모드에서 실행 시, 이는 업데이트를 트리거하는 데 사용할 수 있는 파일시스템 감시자입니다. 자세한 내용은 [`ViteDevServer`](https://ko.vite.dev/guide/api-javascript.html#vitedevserver)를 참조하세요.

```ts title="Extract from the file() loader" {8-13}
return {
  name: 'file-loader',
  load: async ({ config, store, watcher }) => {
    const url = new URL(fileName, config.root);
    const filePath = fileURLToPath(url);
    await syncData(filePath, store);

    watcher?.on('change', async (changedPath) => {
      if (changedPath === filePath) {
        logger.info(`Reloading data from ${fileName}`);
        await syncData(filePath, store);
      }
    });
  },
};
```

#### `refreshContextData`

<p>

**타입**: `Record<string, unknown>`
</p>

로더가 통합에 의해 트리거된 경우, 이는 선택적으로 해당 통합에 의해 설정된 추가 데이터를 포함할 수 있습니다. 이는 로더가 통합에 의해 트리거될 때만 설정됩니다. 자세한 내용은 [`astro:server:setup`](/ko/reference/integrations-reference/#refreshcontent-옵션) 훅 참조를 확인하세요.

```ts title=loader.ts {5-8}
export function myLoader(options: { url: string }): Loader {
  return {
    name: "my-loader",
    load: async ({ refreshContextData, store, logger }) => {
      if(refreshContextData?.webhookBody) {
        logger.info("Webhook triggered with body");
        processWebhook(store, refreshContextData.webhookBody);
      }
      // ...
    },
  };
}
```

### `DataStore`

데이터 스토어는 콘텐츠 컬렉션 데이터에 대한 로더의 인터페이스입니다. 이는 컬렉션 범위의 키-값(KV) 스토어이므로, 로더는 자신의 컬렉션에 대한 데이터에만 접근할 수 있습니다.

#### `get`

<p>

**타입**: <code>(key: string) => <a href="#dataentry">DataEntry</a> | undefined</code>
</p>

스토어에서 ID로 항목을 가져옵니다. 항목이 존재하지 않는 경우 `undefined`를 반환합니다.

```ts
const existingEntry = store.get("my-entry");
```

[`DataEntry`](#dataentry) 객체를 반환합니다.

#### `set`

<p>

**타입**: <code>(entry: <a href="#dataentry">DataEntry</a>) => boolean</code>
</p>

데이터가 [검증되고 파싱](#parsedata)된 후에 스토어에 항목을 추가하는 데 사용되며, 항목이 설정되면 `true`를 반환합니다. [`digest`](#digest) 속성이 항목이 변경되지 않았으며 업데이트할 필요가 없다고 판단할 때는 `false`를 반환합니다.

```ts title=loader.ts {7-14}
    for (const item of feed.items) {
      const data = await parseData({
        id: item.guid,
        data: item,
      });
      const digest = generateDigest(data);
      store.set({
        id,
        data,
        rendered: {
          html: data.description ?? "",
        },
        digest,
      });
    }
```

#### `entries`

<p>

**타입**: `() => Array<[id: string, DataEntry]>`
</p>

컬렉션의 모든 항목을 키-값 쌍의 배열로 가져옵니다.

#### `keys`

<p>

**타입**: `() => Array<string>`
</p>

컬렉션에 있는 항목의 모든 키를 가져옵니다.

#### `values`

<p>

**타입**: `() => Array<DataEntry>`
</p>

컬렉션의 모든 항목을 배열로 가져옵니다.

#### `delete`

<p>

**타입**: `(key: string) => void`
</p>

ID를 사용하여 스토어에서 항목을 삭제합니다.

#### `clear`

<p>

**타입**: `() => void`
</p>

컬렉션에서 모든 항목을 삭제합니다.

#### `has`

<p>

**타입**: `(key: string) => boolean`
</p>

ID로 항목이 스토어에 존재하는지 확인합니다.

### `DataEntry`

데이터 스토어에 저장되는 객체의 타입입니다. 다음과 같은 속성을 가집니다:

#### `id`

<p>

**타입**: `string`
</p>

컬렉션에서 고유해야 하는 항목의 식별자입니다. 이는 스토어에서 항목을 찾는 데 사용되며 해당 컬렉션에서 `getEntry`와 함께 사용되는 키입니다.

#### `data`

<p>

**타입**: `Record<string, unknown>`
</p>

항목의 실제 데이터입니다. 사용자가 컬렉션에 접근할 때, 이는 컬렉션 스키마에 따라 생성된 TypeScript 타입을 가지게 됩니다.

데이터 스토어에 저장하기 전에 [`parseData`](#parsedata)를 사용하여 데이터를 검증하고 파싱하는 것은 로더의 책임입니다: 데이터를 가져오거나 설정할 때는 검증이 수행되지 않습니다.

#### `filePath`

<p>

**타입**: `string | undefined`
</p>

이 항목의 소스가 되는 파일의 경로로, 사이트의 루트를 기준으로 합니다. 이는 파일 기반 로더에만 적용되며 이미지나 다른 자산과 같은 경로를 해결하는 데 사용됩니다.

설정되지 않은 경우, [`image()` 헬퍼](/ko/guides/images/#콘텐츠-컬렉션의-이미지)를 사용하는 스키마의 모든 필드는 [공개 경로](/ko/guides/images/#이미지-저장-위치)로 처리되며 변환되지 않습니다.

#### `body`

<p>

**타입**: `string | undefined`
</p>

해당되는 경우 항목의 원본 본문입니다. 항목이 [렌더링된 콘텐츠](#rendered)를 포함하는 경우, 이 필드는 원본 소스를 저장하는 데 사용될 수 있습니다. 이는 선택사항이며 내부적으로 사용되지 않습니다.

#### `digest`

<p>

**타입**: `string | undefined`
</p>

항목의 선택적 콘텐츠 다이제스트입니다. 이는 데이터가 변경되었는지 확인하는 데 사용될 수 있습니다.

[항목을 설정](#set)할 때, 다이제스트가 동일한 ID를 가진 기존 항목과 일치하지 않는 경우에만 항목이 업데이트됩니다.

다이제스트의 형식은 로더에 따라 다르지만, 데이터가 변경될 때 변경되는 문자열이어야 합니다. 이는 [`generateDigest`](#generatedigest) 함수를 사용하여 수행할 수 있습니다.

#### `rendered`

<p>

**타입**: `RenderedContent | undefined`
</p>

항목이 HTML로 렌더링된 경우 렌더링된 콘텐츠와 메타데이터가 있는 객체를 저장합니다. 예를 들어, 이는 Markdown 항목의 렌더링된 콘텐츠나 CMS의 HTML을 저장하는 데 사용될 수 있습니다.

이 필드가 제공되면, 페이지에서 항목을 렌더링하기 위해 [`render()` 함수와 `<Content />` 컴포넌트](/ko/guides/content-collections/#본문-콘텐츠-렌더링)를 사용할 수 있습니다.

`RenderedContent` 객체의 형식은 다음과 같습니다:

```ts
{
	/** 렌더링된 HTML 문자열입니다. 존재하는 경우 `render(entry)`는 이 HTML을 렌더링하는 컴포넌트를 반환합니다. */
	html: string;
	metadata?: {
		/** 이 항목에 존재하는 모든 이미지입니다. DataEntry의 filePath를 기준으로 합니다. */
		imagePaths?: Array<string>;
		/** 이 파일에 존재하는 모든 제목입니다. `render()`에서 `headings`로 반환됩니다 */
		headings?: MarkdownHeading[];
		/** 파일에서 파싱된 원본 프런트매터입니다. 이는 remark 플러그인의 데이터를 포함할 수 있습니다. */
		frontmatter?: Record<string, any>;
		/** 이 파일에 존재하는 다른 모든 메타데이터입니다. */
		[key: string]: unknown;
	};
}
```

항목에 Markdown 콘텐츠가 있는 경우 [`renderMarkdown()`](#rendermarkdown) 함수를 사용하여 Markdown 문자열에서 이 객체를 생성할 수 있습니다.
